/**
 * Clase ComunicacionHttp: destinada al establecimiento y gestion de las comunicaciones http
 * en la aplicacion
 */

package infbmobile.comunicaciones;

// Importaciones externas
import java.io.*;
import java.util.*;
import javax.microedition.io.*;
import com.sun.lwuit.*;

// Importaciones internas
import infbmobile.pantallas.*;
import infbmobile.util.*;
import infbmobile.almacenamiento.*;
import infbmobile.comunicaciones.CodigosMensajes;
import infbmobile.errores.*;

public class ComunicacionHttp implements Runnable {

    // Constantes que representan las posibles acciones
    public static final int LOGIN=0;
    public static final int ACTUALIZAR_IDENTIFICACION=1;
    public static final int BUSCAR_MEDICAMENTOS=2;

    // Variables de clase
    private static String host="localhost";
    private static String puerto="8080";
    private static String aplicacion="GestionHospitalaria";

    private  String urlConexion="http://"+host+":"+puerto+"/"+aplicacion+"/";
    private String[] nombreParametros;
    private String[] valoresParametros;
    private Thread hilo;
    private boolean modoHebra=false;
    private HttpConnection conexion;
    private Container c;
    private int accion;
    private String codigoRespuesta;

    // Flag para el mantenimiento del estado de la sesion
    private boolean checkSesion=false;

    /**
     * Constructor principal de clase
     */
    public ComunicacionHttp(int accion,String peticion,Container c) {
        this.accion=accion;
        urlConexion+=peticion;
        this.c=c;
    }

    // Metodos getters y setters
    public static void setHost(String host) {
        ComunicacionHttp.host=host;
    }

    public static String getHost() {
        return ComunicacionHttp.host;
    }

    public static void setPuerto(String puerto) {
        ComunicacionHttp.puerto=puerto;
    }

    public static String getPuerto() {
        return ComunicacionHttp.puerto;
    }

    public static void setAplicacion(String aplicacion) {
        ComunicacionHttp.aplicacion=aplicacion;
    }

    public static String getAplicacion() {
        return ComunicacionHttp.aplicacion;
    }

    public String[] getNombreParametros() {
        return nombreParametros;
    }

    public void setNombreParametros(String[] nombreParametros) {
        this.nombreParametros=nombreParametros;
    }

    public String[] getValoresParametros() {
        return valoresParametros;
    }

    public void setValoresParametros(String[] valoresParametros) {
        this.valoresParametros=valoresParametros;
    }

    public void setCheckSesion(boolean checkSesion) {
        this.checkSesion=checkSesion;
    }

    public boolean isCheckSesion() {
        return checkSesion;
    }
    
    public void setAccion(int accion) {
        this.accion=accion;
    }

    public int getAccion() {
        return accion;
    }

    public void setModoHebra(boolean estado) {
        modoHebra=estado;
    }

    public boolean isModoHebra() {
        return modoHebra;
    }

    public String getCodigoRespuesta() {
        return codigoRespuesta;
    }

    /**
     * Metodo para iniciar las comunicaciones
     */
    public void conectar() {
        if(modoHebra){
            hilo=new Thread(this);
            hilo.start();
        }else{
            ejecucionBasica();
        }
    }

    /*
     * Metodo auxiliar que encapsula la logica necesaria para la apertura de una
     * comunicacion http POST desde el dispositivo movil
     */
    private void abrirConexionPOST() {
        try{
            if(checkSesion){
                Identificacion.cargarIdSesion();
                String idSesion=Identificacion.getIdSesion();
                if(idSesion!=null){
                    urlConexion+=";jsessionid="+idSesion;
                }
            }
            conexion=(HttpConnection)Connector.open(urlConexion);
            conexion.setRequestProperty("Content-Language","es-ES");
            conexion.setRequestProperty("User-Agent","Profile/MIDP-2.0 Configuration/CLDC-1.0");
            conexion.setRequestProperty("Connection","close");
            conexion.setRequestMethod(HttpConnection.POST);
            // Envio de parametros a traves del flujo de salida
            DataOutputStream salidaHaciaServidor=conexion.openDataOutputStream();
            if(valoresParametros.length>0){
                for(int i=0;i<valoresParametros.length;i++){
                    salidaHaciaServidor.writeUTF(valoresParametros[i]);
                }
            }
            salidaHaciaServidor.flush();
            // Cerramos el flujo de envio o salida
            salidaHaciaServidor.close();
        }catch(IOException ioe){
            ioe.printStackTrace();
            throw new MovilException("Error: Se produjo un error en la apertura de conexion http POST => "+ioe.getMessage());
        }
    }

    /*
     * Metodo auxiliar que encapsula la logica necesaria para la apertura de una
     * comunicacion http GET desde el dispositivo movil
     */
    private void abrirConexionGET() {
        try{
            if(valoresParametros.length>0){
                for(int i=0;i<valoresParametros.length;i++){
                    urlConexion+=(i==0)?"?":"&";
                    urlConexion+=nombreParametros[i]+"="+valoresParametros[i];
                }
            }
            if(checkSesion){
                Identificacion.cargarIdSesion();
                String idSesion=Identificacion.getIdSesion();
                if(idSesion!=null){
                    urlConexion+=";jsessionid="+idSesion;
                }
            }
            conexion=(HttpConnection)Connector.open(urlConexion);
            conexion.setRequestProperty("Content-Language","es-ES");
            conexion.setRequestProperty("User-Agent","Profile/MIDP-2.0 Configuration/CLDC-1.0");
            conexion.setRequestProperty("Connection","close");
            conexion.setRequestMethod(HttpConnection.GET);
        }catch(IOException ioe){
            ioe.printStackTrace();
            throw new MovilException("Error: Se produjo un error en la apertura de conexion http => "+ioe.getMessage());
        }
    }

    /**
     * Metodo auxiliar utilizado para cerrar la conexion http con el servidor
     */
    private void cerrarConexion() {
        try{
            conexion.close();
        }catch(IOException ioe){
            ioe.printStackTrace();
            throw new MovilException("Error: No se pudo cerrar correctamente la conexion http con el servidor => "+ioe.getMessage());
        }
    }

    /**
     * Metodo auxiliar para procesar el proceso de login
     */
    private void procesarLogin() {
        // El proceso de login se define por seguridad mediante envios POST
        abrirConexionPOST();
        try{
            DataInputStream entradaDesdeServidor=conexion.openDataInputStream();
            codigoRespuesta=entradaDesdeServidor.readUTF();
            // Cerramos el flujo de entrada desde el servidor
            entradaDesdeServidor.close();
        }catch(IOException ioe){
            ioe.printStackTrace();
            throw new MovilException("Error: Se produjo un error en el procesamiento del login => "+ioe.getMessage());
        }
        // Cerramos explicitamente la conexion http
        cerrarConexion();
    }

    /**
     * Metodo auxiliar para procesar el proceso actualizacion de parametros de identificacion
     */
    private void procesarActualizarIdentificacion() {
        // El proceso de login se define por seguridad mediante envios POST
        abrirConexionPOST();
        try{
            DataInputStream entradaDesdeServidor=conexion.openDataInputStream();
            codigoRespuesta=entradaDesdeServidor.readUTF();
            // Dado que este procedimiento se utiliza en modo multihebra, debemos tratar
            if(codigoRespuesta.equalsIgnoreCase(CodigosMensajes.OPERACION_OK)){
                // Si el servidor notifica que no hubo errores, recuperamos los nuevos parametros
                // de identificacion, actualizamos el rms del dispositivo local y mostramos
                // el mensaje de confirmacion al usuario
                String dni=entradaDesdeServidor.readUTF();
                String tarjetaSanitaria=entradaDesdeServidor.readUTF();
                String password=entradaDesdeServidor.readUTF();
                Identificacion.setDni(dni);
                Identificacion.setTarjetaSanitaria(tarjetaSanitaria);
                Identificacion.setPassword(password);
                // Fijamos definitivamente estos parametros en el rms "identificacion"
                Identificacion.establecer();
                UIHerramientas.mostrarAviso("Operacion OK","Ha actualizado sus datos correctamente. Por favor, proceda a reiniciar la aplicacion.");
            }else{
                // Si se produjo algun error
                UIHerramientas.mostrarAviso("Operacion Erronea","Se ha producido un error en el proceso de actualizacion de parametros de identificacion. Intentelo de nuevo");
            }
            // Cerramos el flujo de entrada desde el servidor
            entradaDesdeServidor.close();
        }catch(IOException ioe){
            ioe.printStackTrace();
            throw new MovilException("Error: Se produjo un error en el procesamiento de la actualizacion de identificacion => "+ioe.getMessage());
        }
        // Cerramos explicitamente la conexion http
        cerrarConexion();
    }

     /**
     * Metodo auxiliar para procesar el proceso de busqueda de medicamentos
     */
    private void procesarBusquedaMedicamentos() {
        // El proceso de login se define por seguridad mediante envios POST
        abrirConexionPOST();
        try{
            DataInputStream entradaDesdeServidor=conexion.openDataInputStream();
            PantallaBusquedaMedicamentos p=(PantallaBusquedaMedicamentos)c;
            // Leemos el estado de la sesion
            boolean pacienteRegistrado=entradaDesdeServidor.readBoolean();
            if(!pacienteRegistrado){
                UIHerramientas.mostrarAviso("Error","Para realizar esta accion, usted necesita estar regsitrado. Por favor, pongase en contacto con el servicio tecnico de HospiGest Mobile");
                p.midlet.salir();
            }
            // Leemos el numero de medicamentos recuperados
            int numMedicamentos=entradaDesdeServidor.readInt();
            if(numMedicamentos==0){
                UIHerramientas.mostrarAviso("Busqueda Finalizada","No se encontraron resultados para la busqueda de medicamentos realizada");
            }else{
                // Creamos el hash donde almacenaremos los resultados
                Hashtable resultados=new Hashtable();
                // Procedemos a leer los datos que nos envio el servidor
                for(int i=0;i<numMedicamentos;i++){
                    String id=entradaDesdeServidor.readUTF();
                    String nombre=entradaDesdeServidor.readUTF();
                    String categoria=entradaDesdeServidor.readUTF();
                    String definicion=entradaDesdeServidor.readUTF();
                    String composicion=entradaDesdeServidor.readUTF();
                    String posologia=entradaDesdeServidor.readUTF();
                    String interacciones=entradaDesdeServidor.readUTF();
                    String efectosSecundarios=entradaDesdeServidor.readUTF();
                    String observaciones=entradaDesdeServidor.readUTF();
                    // Formamos el array con todos los parametros del medicamento
                    String[] medicamento=new String[]{id,nombre,categoria,definicion,composicion,posologia,interacciones,efectosSecundarios,observaciones};
                    // Agregamos el medicamento "formado" al hash de resultados
                    Integer indice=new Integer(i);
                    resultados.put(indice,medicamento);
                }
                // Una vez procesados todos los medicamentos hacemos que el resultado de la busqueda
                // sea accesible por la pantalla de busqueda de medicamentos.
                // Esto es realmente la clave del proceso
                UIHerramientas.mostrarAviso("Operacion OK","Se encontraron "+resultados.size()+" medicamentos como resultado de la busqueda");
                p.setResultadosBusqueda(resultados);
                p.mostrarListado();
            }
            // Cerramos el flujo de entrada desde el servidor
            entradaDesdeServidor.close();
        }catch(IOException ioe){
            ioe.printStackTrace();
            throw new MovilException("Error: Se produjo un error en el procesamiento de la busqueda de medicamentos => "+ioe.getMessage());
        }
        // Cerramos explicitamente la conexion http
        cerrarConexion();
    }



    /**
     * Metodo principal de ejecucion para el modo hebra (concurrente)
     */
    public void run() {
        // En funcion de la accion ejecutamos nuestro codigo de procesamiento de respuesta
        // (que es lo que realmente difiere de una accion a otra)
        switch(accion){
            case LOGIN:
                // Procesamiento de la solicitud de login
                procesarLogin();
                break;
            case ACTUALIZAR_IDENTIFICACION:
                // Procesamiento de la solicitud de actualizacion de parametros de identificacion
                procesarActualizarIdentificacion();
                break;
            case BUSCAR_MEDICAMENTOS:
                // Procesamiento de la solicitud de busqueda de medicamentos
                procesarBusquedaMedicamentos();
                break;
            default:
                throw new MovilException("Error: Accion para clase ComunicacionHttp no valida");
        }
    }

    /**
     * Metodo principal de ejecucion para el modo iterativo (modo hebra off)
     */
    public void ejecucionBasica() {
        // En funcion de la accion ejecutamos nuestro codigo de procesamiento de respuesta
        // (que es lo que realmente difiere de una accion a otra)
        switch(accion){
            case LOGIN:
                // Procesamiento de la solicitud de login
                procesarLogin();
                break;
            case ACTUALIZAR_IDENTIFICACION:
                // Procesamiento de la solicitud de actualizacion de parametros de identificacion
                procesarActualizarIdentificacion();
                break;
            case BUSCAR_MEDICAMENTOS:
                // Procesamiento de la solicitud de busqueda de medicamentos
                procesarBusquedaMedicamentos();
                break;
            default:
                throw new MovilException("Error: Accion para clase ComunicacionHttp no valida");
        }
    }

}
